<?php
/*
 * Zend_Itvina_Db_Abstract là lớp cơ sở trong model, là package dữ liệu chuẩn vận chuyển trong mô hình MVC.
 * Là lớp đối tượng chứa các thuộc tính được mapping từ cơ dữ liệu xuống bằng tool generate code của EA 
 * , các phương thức truy xuất đối tượng (__get,__set,__construct,toArray,...), các phương thức truy xuất cơ sở dữ liệu.  
 * Do tổ chức thuộc tính dữ liệu, phương thức truy xuất dữ liệu chung trên 1 lớp,  
 * nên tránh đặt tên các phương thức bắt đầu bằng chữ get hoặc set để tránh xung đột khi truy xuất thuộc tính bằng kĩ thuật reflection, 
 * đặt theo dạng bướu lạc đà (Camel Case).
 */

class Itvina_Model_Abstract
{
	/*
	 * thuộc tính mở rộng cho đối tượng
	 */
	public $m_Array;
	
	/*
	 * câu query gần nhất
	 */
	public $m_Query;

	/*
	 * Khởi tạo đối tượng
	 * */
	public function __construct(array $options = null)
	{
		if (is_array ( $options ))
		{
			Itvina_Model_Abstract::factory ( $options, $this, $this );
		}
		$this->m_Array = array ();
	}

	/*
	 * Ép kiểu hay chuyển đổi đối tượng $input về class chuẩn Zend_Itvina_Db_Abstract 
	 * INPUT: 
	 * - $input: đối tượng cần chuyển đổi
	 * - $output: nếu có truyền vào thì sẽ cập nhật dữ liệu vào đối tượng này, nếu không thì trả ra đối tượng mới 
	 * - $class: xác định class của đối tượng cần trả về
	 * 		+ Nếu không truyền vào thì class trả về là class của $output
	 * 		+ Nếu truyền chuỗi thì class trả về có tên = chuỗi này
	 * 		+ Nếu truyền đối tượng thì class trả về = class của đối tương này
	 * OUTPUT:
	 * - Trả về đối tượng Zend_Itvina_Db_Abstract. Nếu không chuyển đổi được sẽ báo lỗi 	 
	 */
	public static function factory($input, $output_object = null, $output_class = null)
	{
		//nếu không truyền tham số, báo lỗi
		if ($output_class === null && $output_object === null)
		{
			Itvina_Model_Abstract::throwError ( "<<< ITVINA: FUNCTION factory > PARAM output_object AND output_class IS NULL >>>" );
		}
		
		//xác định class của đối tượng cần trả về 
		if ($output_class === null)
		{
			$class = get_class ( $output_object );
		}
		else if (is_string ( $output_class ))
		{
			$class = $output_class;
		}
		else if ($output_class instanceof Itvina_Model_Abstract)
		{
			$class = get_class ( $output_class );
		}
		else
		{
			Itvina_Model_Abstract::throwError ( "<<< ITVINA: FUNCTION factory > PARAM output_class IS WRONG TYPE > " . Zend_Debug::dump ( $output_class, "", false ) . " >>>" );
		}
		
		//xác định đối tượng trả về
		if ($output_object === null)
			$output = new $class ();
		else
			$output = $output_object;
		
		//kiểm tra đối tượng đầu vào
		if ($input instanceof Zend_Db_Table_Row)
		{
			$input = $input->toArray ();
		}
		else if (is_array ( $input ))
		{
		
		}
		else if ($input === null)
		{
			return $output;
		}
		else
		{
			Itvina_Model_Abstract::throwError ( "<<< ITVINA: FUNCTION factory > PARAM input IS WRONG TYPE > " . Zend_Debug::dump ( $output_class, "", false ) . " >>>" );
		}
		
		//tạo đối tượng
		$methods = get_class_methods ( $class );
		foreach ( $input as $field => $value )
		{
			$method = 'set' . ucfirst ( $field );
			if (substr ( $method, 0, 5 ) != 'setM_')
			{
				if (in_array ( $method, $methods ))
				{
					$output->$method ( $value );
				}
				else
				{
					$output->m_Array [$field] = $value;
				}
			}
		}
		
		//trả kết quả về
		if ($output_object === null)
			return $output;
	}

	/*
	 * __get, __set: hỗ trợ truy xuất 1 thuộc tính của đối tượng thông qua cách 	 
	 */
	public function __set($field, $value)
	{
		try
		{
			$method = 'set' . $field;
			$this->$method ( $value );
		}
		catch ( Exception $e )
		{
			$class = get_class ( $this );
			Itvina_Model_Abstract::throwError ( "<<< ITVINA: CLASS " . $class . " DOES NOT HAVE PROPERTY " . $field . " TO SET >>>" );
		}
	}

	public function __get($field)
	{
		try
		{
			$method = 'get' . $field;
			return $this->$method ();
		}
		catch ( Exception $e )
		{
			$class = get_class ( $this );
			Itvina_Model_Abstract::throwError ( "<<< ITVINA: CLASS " . $class . " DOES NOT HAVE PROPERTY " . $field . " TO GET >>>" );
		}
	}
	
	/*
	 * Gắn kết đối tượng Zend_Db_Table_Abstract, hỗ trợ truy xuất csdl
	 */
	protected $_dbTable;

	public function setDbTable($dbTable)
	{
		if (is_string ( $dbTable ))
		{
			$dbTable = new $dbTable ();
		}
		if (! $dbTable instanceof Zend_Db_Table_Abstract)
		{
			Itvina_Model_Abstract::throwError ( "<<< ITVINA: INVALID TABLE DATA GATEWAY PROVIDED >>>" );
		}
		$this->_dbTable = $dbTable;
		return $this;
	}

	public function getDbTable()
	{
		if (null === $this->_dbTable)
		{
			$class = str_replace ( '_Model_', '_Model_DbTable_', get_class ( $this ) );
			$this->setDbTable ( $class );
		}
		return $this->_dbTable;
	}

	/*
     * Chuyển đối tượng ra mảng
     * Dùng khi populate dữ liệu vào các element trong form 
     */
	public function toArray()
	{
		try
		{
			$methods = get_class_methods ( $this );
			$array = array ();
			foreach ( $methods as $method )
			{
				if (substr ( $method, 0, 3 ) == 'get' && $method != 'getDbTable')
				{
					$field = strtolower ( substr ( $method, 3 ) );
					$value = $this->$method ();
					if (isset ( $value ))
						$array [$field] = $value;
				}
			}
			return $array;
		}
		catch ( Exception $e )
		{
			$class = get_class ( $this );
			Itvina_Model_Abstract::throwError ( "<<< ITVINA: CLASS " . $class . " DOES NOT HAVE PROPERTY " . $var . " TO ARRAY >>>" );
		}
	}

	/*
	 * TARGET: Lấy 1 hoặc nhiều dòng (record) theo id
	 * INPUT: 
	 * - Nếu lấy 1 dòng, truyền vào 1 id cần lấy (nếu không truyền thì sẽ lấy id của đối tượng gọi hàm)
	 * - Nếu lấy nhiều dòng, truyền vào 1 mảng id. Ví dụ: array(1,2,3,...) 
	 * OUTPUT:
	 * - Nếu chỉ lấy 1 dòng, cập nhật dữ liệu của dòng tìm thấy vào đối tượng gọi hàm. Nếu không tìm thấy thì return false
	 * - Nếu lấy nhiều dòng, trả về 1 mảng. Nếu không tìm thấy dữ liệu thì mảng trả về có 0 phần tử
	 * EXAMPLE:
	 * - Lấy 1 dòng có id=4
	 * $entry=new Itvina_Model_Abstract();
	 * $entry->findBase(4);
	 * - Không truyền tham số
	 * $entry=new Itvina_Model_Abstract();
	 * $entry->id=4;
	 * $entry->findBase();
	 * - Lấy 3 dòng có id IN (4,5,6)
	 * $entry=new Itvina_Model_Abstract();
	 * $entries=$entry->findBase(array(4,5,6));
	 */
	public function findBase($id = "", $index_field = null)
	{
		
		try
		{
			//kiểm tra có khai báo key chưa?
			$primary = Itvina_Model_Abstract::primary ( $this );
			
			//lấy id của đối tượng nếu không truyền vào
			if ($id == "")
				$id = $this->$primary;
			
		//lấy dữ liệu 
			$result = $this->getDbTable ()->find ( $id );
			if (is_array ( $id )) //trả về mảng
			{
				$entries = array ();
				foreach ( $result as $row )
				{
					$entry = Itvina_Model_Abstract::factory ( $result->current (), null, $this );
					if ($index_field !== null)
						$entries [$entry->$index_field] = $entry;
					else
						$entries [] = $entry;
				}
				return $entries;
			}
			else //trả dữ liệu vào đối tượng gọi hàm
			{
				if ($result->count () == 0)
					return false;
				else
				{
					Itvina_Model_Abstract::factory ( $result->current (), $this, $this );
					return $this;
				}
			}
		}
		catch ( Exception $e )
		{
			Itvina_Model_Abstract::throwError ( $e );
		}
	}

	/*
	 * TARGET: Lấy tất cả dòng (record) thỏa thuộc tính của đối tượng gọi hàm
	 * INPUT: 
	 * - $order: chuỗi hoặc mảng thứ tự cần lấy dữ liệu. Ví dụ: "id ASC" hoặc array("id ASC","name DESC")
	 * - $count: số lượng record muốn lấy
 	 * - $offset: vị trí bắt đầu lấy dữ liệu (đánh số 0 trở lên), tương ứng với mệnh đề "LIMIT $count,$offset"
 	 * OUTPUT: 
 	 * - Trả về 1 mảng đối tượng. Nếu không tìm thấy sẽ trả về mảng 0 phần tử
 	 * EXAMPLE: 
 	 * - Để lấy tất cả dòng thỏa điều kiện cột name='itvina' và cột age=30
 	 * $entry=new Itvina_Model_Abstract();
 	 * $entry->name='itvina';
 	 * $entry->age=30;
 	 * $entries=$entry->fetchBase();
 	 * - Lấy 3 dòng thỏa điều kiện trên và sắp xếp theo thứ tự name tăng dần
 	 * ...
 	 * $entries=$entry->fetchBase('name ASC',3,0);
 	 * - Lấy 10 dòng từ vị trí offset 5 thỏa điều kiện trên và sắp xếp theo thứ tự name tăng dần, age giảm dần
 	 * ...
 	 * $entries=$entry->fetchBase(array('name ASC','age DESC'),0,5); 
	 */
	public function fetchBase($order = null, $count = null, $offset = null)
	{
		try
		{
			$methods = get_class_methods ( $this );
			$where = "1";
			foreach ( $methods as $method )
			{
				if (substr ( $method, 0, 3 ) == "get" && $method != 'getDbTable')
				{
					$field = strtolower ( substr ( $method, 3 ) );
					$value = $this->$method ();
					if ($value !== null)
						$where .= " AND `" . $field . "`='" . $value . "'";
				}
			}
			if ($where == "1")
				return array ();
			else
				return $this->fetchAllBase ( $where, $order, $count, $offset );
		}
		catch ( Exception $e )
		{
			Itvina_Model_Abstract::throwError ( $e );
		}
	}

	/*
	 * TARGET: Tương tự hàm fetchBase, nhưng lấy các record thỏa điều kiện của mệnh đề WHERE truyền vào
	 * INPUT: 
	 * - ... tương tự hàm fetchBase
	 * - $where: mệnh đề điều kiện WHERE. Ví dụ: " name = 'itvina' OR name = 'itv' "
 	 * OUTPUT: 
 	 * - Trả về 1 mảng đối tượng. Nếu không tìm thấy sẽ trả về mảng 0 phần tử
 	 * EXAMPLE: 
 	 * - Để lấy tất cả dòng thỏa điều kiện cột name có chứa chuỗi 'itvina'
 	 * $entry=new Itvina_Model_Abstract();
 	 * $entries=$entry->fetchAllBase(" name LIKE '%itvina%' "); 
	 */
	public function fetchAllBase($where = null, $order = null, $count = null, $offset = null, $index_field = null)
	{
		try
		{
			$this->m_Query = $where;
			$entries = array ();
			$resultSet = $this->getDbTable ()->fetchAll ( $where, $order, $count, $offset );
			foreach ( $resultSet as $row )
			{
				$entry = Itvina_Model_Abstract::factory ( $row, null, $this );
				if ($index_field !== null)
					$entries [$entry->$index_field] = $entry;
				else
					$entries [] = $entry;
			}
			return $entries;
		}
		catch ( Exception $e )
		{
			Itvina_Model_Abstract::throwError ( $e );
		}
	}

	/*
	 * TARGET: Lấy 1 record thỏa thuộc tính của đối tượng gọi hàm, cập nhật dữ liệu vào đối tượng gọi hàm
	 * INPUT:
	 * - $entry: nếu không truyền tham số này thì sẽ cập nhật dòng dữ liệu tìm thấy vào đối tượng gọi hàm, ngược lại sẽ cập nhật vào tham số này 
	 * OUTPUT: 
	 * - Nếu không truyền $entry, Cập nhật dòng dữ liệu tìm thấy vào đối tượng gọi hàm 
	 * - Nếu có truyền $entry vào, cập nhật dòng dữ liệu tìm thấy vào tham số $entry 
	 * - Nếu không tìm thấy thì return false
	 * EXAMPLE: 
	 * Lấy dòng dữ liệu thỏa điều kiện age=5 và fullname='itvina'
	 * $entry=new Itvina_Model_Abstract();
	 * $entry->age=4;
	 * $entry->fullname='itvina'
	 * $entry->fetchRowBase();
	 */
	public function fetchRowBase(&$entry = null)
	{
		try
		{
			$methods = get_class_methods ( $this );
			$where = "1";
			foreach ( $methods as $method )
			{
				if (substr ( $method, 0, 3 ) == "get" && $method != 'getDbTable')
				{
					$field = strtolower ( substr ( $method, 3 ) );
					$value = $this->$method ();
					if (isset ( $value ))
						$where .= " AND `" . $field . "`='" . $value . "'";
				}
			}
			if ($where == "1")
				return false;
			else
			{				
				if ($entry === null)
					return $this->fetchRowAllBase ( $where, null );
				else
					return $this->fetchRowAllBase ( $where, null, $entry );
			}
		}
		catch ( Exception $e )
		{
			Itvina_Model_Abstract::throwError ( $e );
		}
	}

	/*
	 * TARGET: Lấy 1 dòng (record) thỏa thuộc mệnh đề điều kiện WHERE
	 * INPUT:
	 * - $where: mệnh đề điều kiện
	 * - $order: chuỗi hoặc mảng thứ tự cần lấy dữ liệu. Ví dụ: "id ASC" hoặc array("id ASC","name DESC")
	 * - $entry: nếu không truyền tham số này thì sẽ cập nhật dòng dữ liệu tìm thấy vào đối tượng gọi hàm, ngược lại sẽ cập nhật vào tham số này 
	 * OUTPUT: 
	 * - Nếu không truyền $entry, Cập nhật dòng dữ liệu tìm thấy vào đối tượng gọi hàm 
	 * - Nếu có truyền $entry vào, cập nhật dòng dữ liệu tìm thấy vào tham số $entry 
	 * - Nếu không tìm thấy thì return false
	 * EXAMPLE: 
	 * Lấy dòng dữ liệu thỏa điều kiện age=5 và fullname='itvina'
	 * $entry=new Itvina_Model_Abstract();
	 * $entry->age=4;
	 * $entry->fullname='itvina'
	 * $entry->fetchRowAllBase(" age=4 AND fullname='itvina' ");
	 * Lấy dòng dữ liệu thỏa điều kiện trên và trả vào đối tượng khác là $entry2
	 * ...
	 * $entry2 = new Itvina_Model_Abstract();
	 * $entry->fetchRowAllBase(" age=4 AND fullname='itvina' ",$entry2);
	 */
	public function fetchRowAllBase($where = null, $order = null, &$entry = null)
	{
		try
		{
			$this->m_Query = $where;
			$resultSet = $this->getDbTable ()->fetchRow ( $where, $order );
			if (func_num_args () > 2)
			{
				if (count ( $resultSet ) == 0)
					return false;
				else
				{
					$class = get_class ( $this );
					if ($entry === null)
						$entry = new $class ();
					Itvina_Model_Abstract::factory ( $resultSet, $entry, $this );
					return true;
				}
			}
			else
			{
				if (count ( $resultSet ) == 0)
					return false;
				else
				{
					Itvina_Model_Abstract::factory ( $resultSet, $this, $this );
					return true;
				}
			}
		}
		catch ( Exception $e )
		{
			Itvina_Model_Abstract::throwError ( $e );
		}
	}

	/*
	 * TARGET: lấy 1 giá trị duy nhất. Trên dòng đầu tiên thỏa điều kiện $where, sẽ lấy giá trị cột $column chỉ định
	 * REFERENCE: tham khảo hàm fetchOne của defaultAdapter 
	 * INPUT:
	 * - $where: mệnh đề điều kiện
	 * - $column: cột cần lấy dữ liệu 
	 * - $default: giá trị mặc định trả về nếu không tìm thấy kết quả
	 * OUTPUT: 
	 * - Không tìm thấy trả về $default
	 * EXAMPLE: 
	 * Lấy name thỏa điều kiện id=5
	 * $entry=new Itvina_Model_Abstract();
	 * $name=$entry->fetchOneBase("name"," id=5 ");
	 */
	
	public function fetchOneBase($column, $where = null, $default = null)
	{
		try
		{
			$this->m_Query = $where;
			$table_name = $this->getDbTable ()->_name;
			$sql = "SELECT $column FROM $table_name WHERE $where";
			$result=$this->getDbTable ()->getDefaultAdapter ()->fetchOne ( $sql );
			return $result === false?$default:$result;
		}
		catch ( Exception $e )
		{
			Itvina_Model_Abstract::throwError ( $e );
		}
	}
	
	public function fetchOne($sql,$bind=array())
	{
		try
		{
			return $this->getDbTable ()->getDefaultAdapter ()->fetchOne ( $sql ,$bind);
		}
		catch ( Exception $e )
		{
			Itvina_Model_Abstract::throwError ( $e );
		}
	}

	/*
	 * Thêm 1 record
	 */
	public function insertBase()
	{
		try
		{
			$methods = get_class_methods ( $this );
			$primary = Itvina_Model_Abstract::primary ( $this );
			foreach ( $methods as $method )
			{
				if (substr ( $method, 0, 3 ) == "get" && strtolower ( $method ) != "get$primary" && $method != 'getDbTable')
				{
					$value = $this->$method ();
					if ($value !== null)
					{
						$field = strtolower ( substr ( $method, 3 ) );
						$data [$field] = $value;
					}
				}
			}
			$this->$primary = $this->getDbTable ()->insert ( $data );
		}
		catch ( Exception $e )
		{
			Itvina_Model_Abstract::throwError ( $e );
		}
	}

	/*
	 * Cập nhật tất cả record theo mệnh đề điều kiện $where
	 */
	public function updateAllBase($where)
	{
		try
		{
			$this->m_Query = $where;
			$data = array ();
			$methods = get_class_methods ( $this );
			$primary = Itvina_Model_Abstract::primary ( $this );
			foreach ( $methods as $method )
			{
				/* lấy những phương thức get dữ liệu mà thôi
            	 * không get id, do không update id
            	 * không lấy hàm getDbTable, do hàm này không lấy dữ liệu
            	 */
				
				if (substr ( $method, 0, 3 ) == "get" && strtolower ( $method ) != "get$primary" && $method != 'getDbTable')
				{
					$field = strtolower ( substr ( $method, 3 ) );
					$value = $this->$method ();
					if ($value !== null)
						$data [$field] = $value;
				}
			}
			if (count ( $data ) > 0)
				return $this->getDbTable ()->update ( $data, $where );
			else
				return 0;
		}
		catch ( Exception $e )
		{
			Itvina_Model_Abstract::throwError ( $e );
		}
	}

	/*
	 * Cập nhật 1 record theo khoa chính
	 */
	public function updateBase()
	{
		//kiểm tra có khai báo key chưa?
		$primary = Itvina_Model_Abstract::primary ( $this );
		
		//lấy tham số id
		$args = func_get_args ();
		switch (count ( $args ))
		{
			case 0 : //không truyền tham số
				$id = $this->$primary;
				$where = "`$primary`='$id'";
				break;
			case 1 : //có truyền 1 id hoặc mảng id
				$id = $args [0];
				if (is_array ( $id ))
					$str_id = implode ( ",", $id );
				else
					$str_id = $id;
				$where = "`$primary` IN ($str_id)";
				break;
		}
		
		//cap nhat lieu
		return $this->updateAllBase ( $where );
	}

	/*
	 * Xóa nhiều record theo mảng id truyền vào và trả ra số lượng row bị ảnh hưởng
	 */
	public function deleteBase()
	{
		try
		{
			//kiểm tra có khai báo key chưa?
			$primary = Itvina_Model_Abstract::primary ( $this );
			
			//lấy tham số id
			$args = func_get_args ();
			switch (count ( $args ))
			{
				case 0 : //không truyền tham số
					$id = $this->$primary;
					$where = "`$primary`='$id'";
					break;
				case 1 : //có truyền 1 id hoặc mảng id
					$id = $args [0];
					if (is_array ( $id ))
						$str_id = implode ( ",", $id );
					else
						$str_id = $id;
					$where = "`$primary` IN ($str_id)";
					break;
			}
			
			//xoa du lieu
			return $this->deleteAllBase ( $where );
		}
		catch ( Exception $e )
		{
			Itvina_Model_Abstract::throwError ( $e );
		}
	}

	/*
	 * Xóa nhiều record theo mệnh đề điều kiện $where và trả ra số lượng row bị ảnh hưởng
	 */
	public function deleteAllBase($where)
	{
		try
		{
			$this->m_Query = $where;
			return $this->getDbTable ()->delete ( $where );
		}
		catch ( Exception $e )
		{
			Itvina_Model_Abstract::throwError ( $e );
		}
	}

	/*
	 * Lấy số lượng record theo câu điều kiện
	 */
	public function countBase($where = null, $default = null)
	{
		return $this->calculateBase ( "COUNT", "*", $where, $default );
	}

	/*
	 * Lấy max bieu thuc theo dieu kien 
	 */
	public function maxBase($content, $where = null, $default = null)
	{
		return $this->calculateBase ( "MAX", $content, $where, $default );
	}

	/*
	 * Lấy min bieu thuc theo dieu kien 
	 */
	public function minBase($content, $where = null, $default = null)
	{
		return $this->calculateBase ( "MIN", $content, $where, $default );
	}

	/*
	 * Tinh sum bieu thuc theo dieu kien 
	 */
	public function sumBase($content, $where = null, $default = null)
	{
		return $this->calculateBase ( "SUM", $content, $where, $default );
	}

	/*
	 * Tinh toan du lieu theo dieu kien
	 * $where: dieu kien
	 * $keyword: tu khoa nhu max,sum,avg,count  
	 * $content: bieu thuc can tinh toan
	 */
	private function calculateBase($keyword, $content, $where, $default = null)
	{
		try
		{
			$this->m_Query = $where;
			if ($content != "*")
				$content = "`$content`";
			$select = $this->getDbTable ()->select ()->from ( $this->getDbTable (), new Zend_Db_Expr ( $keyword . "(" . $content . ") as number" ) );
			if ($where != null)
				$select->where ( $where );
			$row = $this->getDbTable ()->fetchRow ( $select );
			if (! $row || $row->number == null)
				return $default;
			else
				return $row->number;
		}
		catch ( Exception $e )
		{
			Itvina_Model_Abstract::throwError ( $e );
		}
	}

	/*
	 * quăng lỗi
	 */
	static public function throwError($e)
	{
		if ($e instanceof Exception)
			throw $e;
		else
			throw new Exception ( $e );
	}
	
	/*
	 * Sắp xếp thứ tự dựa vào mảng $orders truyền vào
	 * Mỗi phần tử của mảng order là 1 chỉ tiêu sắp xếp
	 */
	private $_arrayOrder;

	private function comparison($a, $b)
	{
		foreach ( $this->_arrayOrder as $value )
		{
			if (strpos ( $value, "ASC" ) === false && strpos ( $value, "DESC" ) === false)
			{
				Itvina_Model_Abstract::throwError ( "<<< ITVINA: ORDER STRING MUST CONTAIN KEYWORD 'DESC' OR 'ASC' >>>" );
				return;
			}
			if (strpos ( $value, "ASC" ) !== false)
			{
				$column = trim ( str_replace ( "ASC", "", $value ) );
				$order = "ASC";
			}
			else
			{
				$column = trim ( str_replace ( "DESC", "", $value ) );
				$order = "DESC";
			}
			if (strpos ( $value, "m_Array[" ) !== false)
			{
				$aValue = $a->m_Array [substr ( $column, 8, strlen ( $column ) - 9 )];
				$bValue = $b->m_Array [substr ( $column, 8, strlen ( $column ) - 9 )];
			}
			else
			{
				$aValue = $a->$column;
				$bValue = $b->$column;
			}
			if ($aValue !== $bValue)
			{
				if ($order == "ASC")
					$result = ($aValue < $bValue) ? - 1 : 1;
				else
					$result = ($bValue < $aValue) ? - 1 : 1;
				return $result;
			}
		}
		return 0;
	}

	public function sortBy(&$array, $orders)
	{
		$this->_arrayOrder = $orders;
		usort ( $array, array (

		$this, 'comparison' ) );
	}

	public function queryBase($sql, $type = 0, $index_field = null)
	{
		$this->m_Query = $sql;
		$adapter = $this->getDbTable ()->getDefaultAdapter ();
		if ($type == 0)
		{
			$rows = $adapter->fetchAll ( $sql );
			$entries = array ();
			foreach ( $rows as $row )
			{
				$entry = Itvina_Model_Abstract::factory ( $row, null, $this );
				if ($index_field !== null)
					$entries [$entry->$index_field] = $entry;
				else
					$entries [] = $entry;
			}
			return $entries;
		}
		else if ($type == 1)
		{
			return $adapter->query ( $sql );
		}
	}

	public function isExist()
	{
		$args = func_get_args ();
		switch (count ( $args ))
		{
			case 2 :
				$count = $this->countBase ( "`$args[0]`='$args[1]'", 0 );
				break;
			case 1 :
				$count = $this->countBase ( $args [0], 0 );
				break;
			default :
				Itvina_Model_Abstract::throwError ( "<<< ITVINA: FUNCTION isExist > MISS PARAM(S) >>>" );
				break;
		}
		return $count > 0;
	}

	static public function toArray2($array, $key = null, $value)
	{
		$eval = strpos ( $value, '$' ) !== false;
		$key_eval = strpos ( $key, '$' ) !== false;
		$result = array ();
		foreach ( $array as $row )
		{
			if ($key === null)
			{
				
				if ($eval)
					eval ( "\$new_value=\"$value\";" );
				else
					$new_value = $row->$value;
				$result [] = $new_value;
			}
			else
			{
				if ($eval)
					eval ( "\$new_value=\"$value\";" );
				else
					$new_value = $row->$value;
				if ($key_eval)
				{
					eval ( "\$new_key=\"$key\";" );
				}
				else
					$new_key = $row->$key;
				$result [$new_key] = $new_value;
			}
		}
		return $result;
	}

	static private function primary($object)
	{
		$primary = $object->getDbTable ()->_primary;
		if (is_array ( $primary ))
		{
			$primary = array_values ( $primary );
			$primary = $primary [0];
		}
		if ($primary == "")
		{
			$class = get_class ( $this );
			Itvina_Model_Abstract::throwError ( "<<< ITVINA: CLASS " . $class . " DOES NOT DEFINE KEY >>>" );
		}
		return $primary;
	}

	static public function settype($value, $type)
	{
		if ($value !== null)
		{
			switch ($type)
			{
				case Itvina_Model_Abstract::TIME :
					if (! is_numeric ( $value ))
					{
						$value = str_replace(array("/"," "), ".", $value);
						$value = strtotime ( $value );
					}
					break;
				case Itvina_Model_Abstract::NUMERIC :
					$value = str_replace ( ".", "", $value );
					$value = str_replace ( ",", ".", $value );
					break;
			}
		}
		
		return $value;
	}
	
	const TIME = 0;
	const NUMERIC = 1;
}
?>